/* wrap.c - Copyright (c) 2007 Helmar Wodtke
   license: MIT
   purpose: provide some screen io functionality for a FORTH system */

#include <stdio.h>
#include "wrap.h"
#ifdef HAVE_CURSES
#  include <curses.h>
#endif
#ifdef HAVE_XCURSES
#  define HAVE_CURSES
#  define NCURSES_MOUSE_VERSION
#  include <curses.h>
#endif
#ifdef NCURSES_MOUSE_VERSION
#  ifdef NO_MOUSE
#    undef NCURSES_MOUSE_VERSION
#  endif
#endif

#ifdef HAVE_CURSES
static int colors[8] = {
  COLOR_BLACK,
  COLOR_RED,
  COLOR_GREEN,
  COLOR_YELLOW,
  COLOR_BLUE,
  COLOR_MAGENTA,
  COLOR_CYAN,
  COLOR_WHITE
};
#endif

cell wrap_var_iomode = DEFAULT_MODE;
#ifdef HAVE_CURSES
int wrap_var_has_initscr = 0;
#endif /* HAVE_CURSES */

void wrap_at_xy(cell x, cell y)
{
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) {
    move(x, y);
    return;
  }
#endif
  printf("\x1B[%d;%dH", (int) x, (int) y);
  return;
}

cell wrap_getx(void)
{
  cell x = 0, y;
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) getyx(stdscr, x, y);
#endif
  return x;
}

cell wrap_gety(void)
{
  cell x, y = 0;
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) getyx(stdscr, x, y);
#endif
  return y;
}

void wrap_emit(cell n)
{
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) {
    addch((char) n);
    return;
  }
#endif
  putchar((int) n);
  return;
}

void wrap_type(cell p, cell n)
{
#if 0
  addchnstr((void *)p, n);
#else
  char *c = (char *)p;
  while (n-- > 0) wrap_emit(*(c++));
#endif
  return;
}

void wrap_flush(void)
{
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) {
    refresh();
    return;
  }
#endif
  fflush(stdout);
  return;
}

void wrap_page(void)
{
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) {
    clear();
    return;
  }
#endif
  printf("\x1B[2J\x1B[H");
  return;
}

#ifdef NCURSES_MOUSE_VERSION
static MEVENT mevent;
static cell mstate;
#endif

cell wrap_key(void)
{
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) {
    cell r = (cell) (getch());
#  ifdef WINFIX
/* That made me near crazy. I still dont know, why it's like is is... */
    r &= 0x3FF;
#  endif
#  ifdef NCURSES_MOUSE_VERSION
    if (r == KEY_MOUSE) mstate = (cell)getmouse(&mevent);
#  endif
    return r;
  }
#endif
  return (cell) getchar();
}

cell wrap_mouse_button(void) {
#ifdef NCURSES_MOUSE_VERSION
  switch(mevent.bstate) {
    case BUTTON1_PRESSED: return M_LKEY;
# ifndef HAVE_XCURSES
    case BUTTON2_PRESSED: return M_DN;
# endif
    case BUTTON3_PRESSED: return M_RKEY;
    case BUTTON4_PRESSED: return M_UP;
# ifdef HAVE_XCURSES
    case BUTTON5_PRESSED: return M_DN;
# endif
  }
#endif
  return 0;
}

cell wrap_xkey(void)
{
#ifdef HAVE_CURSES
  cell r;
  while ((r = wrap_key()) != ERR) {
    switch(r) {
        case KEY_DOWN:      return K_DN;
        case KEY_UP:        return K_UP;
        case KEY_LEFT:      return K_LEFT;
        case KEY_RIGHT:     return K_RIGHT;
        case KEY_NPAGE:     return K_PGDN;
        case KEY_PPAGE:     return K_PGUP;
#  ifndef HAVE_XCURSES
        case 127:
#  endif
        case KEY_BACKSPACE: return BACKSPACE;
        case KEY_HOME:      return K_POS1;
        case KEY_END:       return K_END;
        case KEY_MOUSE:     return K_MOUSE;
        case 8:             return BACKSPACE;
        case 13:            return 10;
    }
    if (r < 256) return r;
  }
  return 0;
#else
  return  wrap_key();
#endif
}

cell old_color = 0;

void wrap_iomode(cell m)
{
  if (m == wrap_var_iomode) return;
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) {
    def_prog_mode();
    endwin();
  }
  if (m == MODE_CUR) {
    if (wrap_var_has_initscr == 0) {
      initscr();
      raw();
      keypad(stdscr, TRUE);
      noecho();
      start_color();
      wrap_var_has_initscr = -1;
      old_color = 0;
    } else refresh();
  }
#endif
  wrap_var_iomode = m;
  return;
}

void wrap_color(cell no) {
#ifdef HAVE_CURSES
  if (wrap_var_iomode == MODE_CUR) {
    if (old_color) attroff(old_color);
    init_pair(no, colors[no&7], colors[(no>>3)&7]);
    if (no) attron((old_color = COLOR_PAIR(no)));
    else old_color = 0;
  }
#endif
  return;
}

cell wrap_mousex(void) {
#ifdef NCURSES_MOUSE_VERSION
  return (cell) mevent.x;
#else
  return 0;
#endif
}

cell wrap_mousey(void) {
#ifdef NCURSES_MOUSE_VERSION
  return (cell) mevent.y;
#else
  return 0;
#endif
}

cell wrap_mousez(void) {
#ifdef NCURSES_MOUSE_VERSION
  return (cell) mevent.z;
#else
  return 0;
#endif
}

cell wrap_mouse_bstate(void) {
#ifdef NCURSES_MOUSE_VERSION
  return (cell) mevent.bstate;
#else
  return 0;
#endif
}

cell wrap_use_nc_mouse(void) {
#ifdef NCURSES_MOUSE_VERSION
  mousemask(ALL_MOUSE_EVENTS, NULL);
  mouseinterval(0);
  return -1;
#else
  return 0;
#endif
}

cell wrap_mstate(void) {
#ifdef NCURSES_MOUSE_VERSION
  return mstate;
#endif
  return 0;
}
